package com.wisecoach.gatewayplus.spring.boot.autoconfigure.event;

import com.wisecoach.gatewayplus.event.*;
import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Map;

/**
 * 该类用于配置 直接监听peer节点 的功能
 * {@code @author:} wisecoach
 * {@code @date:} 2023/9/22 上午11:07
 * {@code @version:} 1.0.0
 */
@Configuration
@EnableConfigurationProperties({GatewayPlusEventProperties.class})
public class GatewayPlusEventSourceConfiguration {

    private final GatewayPlusEventProperties eventProperties;

    public GatewayPlusEventSourceConfiguration(GatewayPlusEventProperties eventProperties) {
        this.eventProperties = eventProperties;
    }

    @Bean
    @ConditionalOnMissingBean(value = {ProgressRecorder.class})
    public ProgressRecorder progressRecorder() {
        return new NoOpProgressRecorder();
    }

    @Bean
    public FilteredBlockEventMulticaster filteredBlockEventMulticaster(ProgressRecorder progressRecorder) {
        return new BlockedFilteredBlockEventMulticaster(progressRecorder);
    }

    @Bean
    public FilteredBlockSourceRegistry filteredBlockSourceRegistry() {
        FilteredBlockSourceRegistry registry = new FilteredBlockSourceRegistry();
        DefaultFilteredBlockSourceFactory factory = new DefaultFilteredBlockSourceFactory();
        Map<String, FilteredBlockSourceInfo> sources = eventProperties.getBlockSources();
        if (!CollectionUtils.isEmpty(sources)) {
            sources.forEach((channelName, sourceInfo) -> {
                FilteredBlockSource source = factory.getSource(sourceInfo);
                registry.register(channelName, source);
            });
        }
        return registry;
    }

    @Configuration
    public static class AutoConfigureRegistryManager implements ApplicationContextAware {

        private ApplicationContext ctx;
        private FilteredBlockEventPublisher publisher;

        @ConditionalOnMissingClass
        @Bean
        @SuppressWarnings({"type"})
        public FilteredBlockEventPublisher filteredBlockEventPublisher(
                FilteredBlockEventMulticaster multicaster,
                FilteredBlockSourceRegistry registry
        ) {
            DefaultFilteredBlockEventPublisher publisher = new DefaultFilteredBlockEventPublisher(multicaster, registry);
            Arrays.stream(ctx.getBeanNamesForType(FilteredBlockEventListener.class)).forEach(name -> {
                FilteredBlockEventListener listener = ctx.getBean(name, FilteredBlockEventListener.class);
                publisher.addListener(listener.getChannelName(), listener);
            });
            this.publisher = publisher;
            return publisher;
        }

        @EventListener
        public void startOnApplicationRefreshed(ContextRefreshedEvent event) {
            publisher.start();
        }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.ctx = applicationContext;
        }
    }

}
